/**	
 * タイトル：csv工具类	
 * 説明：    	
 *			
 * 会社名：	紹興日創軟件有限公司
 * 変更履歴：	2014/09/01 NIS 何
 *			新規作成
 *
 */
package com.nissoft.framework.util;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;

/**
 * @author NIS 何
 * @version 1.0
 */
public class CSVUtil {

	public static final char CHAR_COMMA = ',';
	public static final char CHAR_QUOTE = '\"';
	public static final String COMMA = CHAR_COMMA + "";
	public static final String QUOTE = CHAR_QUOTE + "";

	public static void write(File file, List<List<String>> data)
			throws IOException {
		write(file, data, Charset.defaultCharset(), false);
	}

	/**
	 * 写入csv文件
	 * 
	 * @param file
	 *            文件
	 * @param data
	 *            数据
	 * @param charsetName
	 *            字符集
	 * @throws IOException
	 */
	public static void write(File file, List<List<String>> data,
			String charsetName) throws IOException {
		write(file, data, Charset.forName(charsetName), false);
	}

	public static void write(File file, List<List<String>> data,
			Charset charset, boolean append) throws IOException {

		List<String> lines = new ArrayList<>();
		for (List<String> line : data) {
			List<String> temp = new ArrayList<>();
			for (String s : line) {
				temp.add(writeConvert(s));
			}
			lines.add(StringUtil.join(temp.toArray(), COMMA));
		}
		FileUtil.writeLines(file, lines, charset, append);
	}

	public static List<List<String>> read(File file) throws IOException {
		return read(file, Charset.defaultCharset().toString());
	}

	/**
	 * 读取csv文件
	 * 
	 * @param file
	 *            文件
	 * @param charsetName
	 *            字符集
	 * @throws IOException
	 */
	public static List<List<String>> read(File file, String charsetName)
			throws IOException {

		List<String> lines = FileUtil.readLines(file, charsetName);
		List<List<String>> data = new ArrayList<>();
		for (String line : lines) {
			data.add(split(line));
		}
		return data;
	}

	private static String writeConvert(String str) {

		if (str.indexOf(COMMA) != -1 || str.indexOf(QUOTE) != -1) {
			if (str.indexOf(QUOTE) != -1) {
				str = str.replaceAll(QUOTE, QUOTE + QUOTE);
			}
			str = QUOTE + str + QUOTE;
		}
		return str;
	}

	private static List<String> split(String line) {

		if (StringUtil.isEmpty(line)) {
			return new ArrayList<String>();
		}

		StringReader r = new StringReader(line);
		List<String> items = new ArrayList<>();

		if (line.startsWith(COMMA)) {
			items.add("");
		}

		try {
			int c = 0;
			while ((c = r.read()) != -1) {
				switch (c) {
				case CHAR_QUOTE:
					items.add(parseEscapeString(r));
					break;
				case CHAR_COMMA:
					break;
				default:
					items.add(parseSimpleString(r, c));
				}
			}
		} catch (IOException e) {
		}

		if (line.endsWith(COMMA)) {
			items.add("");
		}
		return items;
	}

	private static String parseEscapeString(StringReader r) throws IOException {
		StringBuffer sb = new StringBuffer();
		int c = 0;
		while ((c = r.read()) != -1) {
			if (c == CHAR_QUOTE) {
				int h = lookAhead(r);
				if (h != CHAR_QUOTE)
					break;
				sb.append((char) r.read());
			} else {
				sb.append((char) c);
			}
		}
		return sb.toString();
	}

	private static String parseSimpleString(StringReader r, int c)
			throws IOException {

		StringBuffer sb = new StringBuffer();
		sb.append((char) c);
		while ((c = r.read()) != -1) {
			if (c == CHAR_COMMA) {
				break;
			}
			sb.append((char) c);
		}
		return sb.toString();
	}

	private static int lookAhead(Reader r) throws IOException {
		r.mark(1);
		int i = r.read();
		r.reset();
		return i;
	}
}
